/*
 * Copyright 2012 Rivoli team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.rivoli.document.renderer.text

import com.googlecode.rivoli.document.ListItem
import com.googlecode.rivoli.document.OrderedList
import com.googlecode.rivoli.document.OrderedList.Type
import com.googlecode.rivoli.model.classhierarchy.RendererFor

@RendererFor(OrderedList)
class OrderedListRenderer extends AbstractTextRenderer<OrderedList> {
	private Map<Type, TypeRenderer> typeRenderers

	OrderedListRenderer() {
		typeRenderers = new EnumMap<Type, TypeRenderer>(Type)
		typeRenderers[Type.ARABIC] = new ArabicTypeRenderer()
		typeRenderers[Type.ALPHABETIC] = new AlphabeticTypeRenderer()
	}

	protected List<String> render(OrderedList list, int width) {
		List<String> lines = []

		TypeRenderer typeRenderer = typeRenderers[typeRenderers.containsKey(list.type) ? list.type : Type.ARABIC]

		int indentationLength = typeRenderer.render(list.items.size()).length()
		String indentation = ' ' * indentationLength

		list.items.eachWithIndex {ListItem item, int itemIndex ->
			String itemLabel = typeRenderer.render(itemIndex + 1)

			int prefixIndentationLength = indentationLength - itemLabel.length()
			String prefixIndentation = ' ' * prefixIndentationLength

			getRenderer(item).render(getElement(item), width - prefixIndentationLength).eachWithIndex {String line, int index ->
				String prefix = (index == 0) ? "${prefixIndentation}${itemLabel}." : indentation

				lines << "${prefix} ${line}"
			}
		}

		lines
	}

	private static interface TypeRenderer {
		String render(int itemNumber)
	}

	private static class ArabicTypeRenderer implements TypeRenderer {
		String render(int itemNumber) {
			"${itemNumber}"
		}
	}

	private static class AlphabeticTypeRenderer implements TypeRenderer {
		String render(int itemNumber) {
			StringBuilder builder = new StringBuilder()

			renderDigit(builder, itemNumber)

			builder.toString()
		}

		private void renderDigit(StringBuilder builder, int itemNumber) {
			if (itemNumber > 0) {
				renderDigit(builder, (int) ((itemNumber - 1) / LETTERS_IN_ALPHABET))

				builder << (char) ((itemNumber - 1) % LETTERS_IN_ALPHABET + ('a' as char))
			}
		}

		private final static int LETTERS_IN_ALPHABET = 26
	}
}